#include "FormModel.h"
#include <QLineEdit>
#include <QTextEdit>
#include <QPlainTextEdit>
#include <QDateTimeEdit>
#include <QComboBox>
#include <QSpinBox>
#include <QDoubleSpinBox>
#include <QCheckBox>
#include <QTableWidgetItem>

#include "Table.h"

using namespace Qy;

FormModel::FormModel(Table* table, QObject *parent) : QObject(parent), table(table)
{
    if(table) table->setParent(this);
}

void FormModel::connect(QWidget *inputWidget, const QString &fieldName, FormModelType type, const QString& QDateTimeForceStringFormat)
{
    if(hashInputWidget.contains(fieldName)) return;
    listFieldName.append(fieldName);
    hashInputWidget.insert(fieldName, inputWidget);
    inputWidget->setProperty("FormModelType", type);
    if(!QDateTimeForceStringFormat.isEmpty()) inputWidget->setProperty("ForceString", QDateTimeForceStringFormat);
}

void FormModel::connect(QTableWidget *table, QTableWidgetItem *item, const QString &fieldName)
{
    connect(table, fieldName, QTableWidgetItemType);
    hashTableItem.insert(fieldName, item);
}

void FormModel::getData(const QString &fieldName, bool directChange)
{
    QWidget *inputWidget = hashInputWidget.value(fieldName);
    switch (inputWidget->property("FormModelType").toInt()) {
    case QLineEditType: {
        QString data = dynamic_cast<QLineEdit*>(inputWidget)->text();
        if(hashGetFilter.contains(QLineEditType)){
            data = hashGetFilter.value(QLineEditType)(data, inputWidget).toString();
        }
        if(directChange || data != table->getFieldValue(fieldName).toString()){
            table->setFieldValue(fieldName, data);
        }
    }break;
    case QTextEditType: {
        QString data = dynamic_cast<QTextEdit*>(inputWidget)->toPlainText();
        if(hashGetFilter.contains(QTextEditType)){
            data = hashGetFilter.value(QTextEditType)(data, inputWidget).toString();
        }
        if(directChange || data != table->getFieldValue(fieldName).toString()){
            table->setFieldValue(fieldName, data);
        }
    }break;
    case QPlainTextEditType: {
        QString data = dynamic_cast<QPlainTextEdit*>(inputWidget)->toPlainText();
        if(hashGetFilter.contains(QPlainTextEditType)){
            data = hashGetFilter.value(QPlainTextEditType)(data, inputWidget).toString();
        }
        if(directChange || data != table->getFieldValue(fieldName).toString()){
            table->setFieldValue(fieldName, data);
        }
    }break;
    case QDateTimeEditType: {
        QString QDateTimeForceStringFormat = inputWidget->property("ForceString").toString();
        QDateTimeEdit* dateTimeEdit = dynamic_cast<QDateTimeEdit*>(inputWidget);
        QDateTime data = dateTimeEdit->dateTime();
        if(hashGetFilter.contains(QDateTimeEditType)){
            data = hashGetFilter.value(QDateTimeEditType)(data, inputWidget).toDateTime();
        }
        if(QDateTimeForceStringFormat.isEmpty()){
            if(directChange || dateTimeEdit->dateTime() != table->getFieldValue(fieldName).toDateTime()){
                table->setFieldValue(fieldName, data);
            }
        }else{
            QString tdata = (data == dateTimeEdit->minimumDateTime() ? "" :
                            data.toString(QDateTimeForceStringFormat));
            if(directChange || tdata != table->getFieldValue(fieldName).toString()){
                table->setFieldValue(fieldName, tdata);
            }
        }
    }break;
    case QComboBoxType: {
        QString data = dynamic_cast<QComboBox*>(inputWidget)->currentText();
        if(hashGetFilter.contains(QComboBoxType)){
            data = hashGetFilter.value(QComboBoxType)(data, inputWidget).toString();
        }
        if(directChange || data != table->getFieldValue(fieldName).toString()){
            table->setFieldValue(fieldName, data);
        }
    }break;
    case QSpinBoxType: {
        int data = dynamic_cast<QSpinBox*>(inputWidget)->value();
        if(hashGetFilter.contains(QSpinBoxType)){
            data = hashGetFilter.value(QSpinBoxType)(data, inputWidget).toInt();
        }
        if(directChange || data != table->getFieldValue(fieldName).toInt()){
            table->setFieldValue(fieldName, data);
        }
    }break;
    case QDoubleSpinBoxType: {
        double data = dynamic_cast<QDoubleSpinBox*>(inputWidget)->value();
        if(hashGetFilter.contains(QDoubleSpinBoxType)){
            data = hashGetFilter.value(QDoubleSpinBoxType)(data, inputWidget).toDouble();
        }
        if(directChange || qFuzzyCompare(data, table->getFieldValue(fieldName).toDouble())){
            table->setFieldValue(fieldName, data);
        }
    }break;
    case QCheckBoxType: {
        bool data = dynamic_cast<QCheckBox*>(inputWidget)->isChecked();
        if(hashGetFilter.contains(QCheckBoxType)){
            data = hashGetFilter.value(QCheckBoxType)(data, inputWidget).toBool();
        }
        if(directChange || data != table->getFieldValue(fieldName).toBool()){
            table->setFieldValue(fieldName, data);
        }
    }break;
    case QTableWidgetItemType: {
        QTableWidgetItem* item = hashTableItem.value(fieldName);
        QString data = item->text();
        if(hashGetFilter.contains(QTableWidgetItemType)){
            data = hashGetFilter.value(QTableWidgetItemType)(data, reinterpret_cast<QWidget*>(item)).toString();
        }
        if(directChange || data != table->getFieldValue(fieldName).toString()){
            table->setFieldValue(fieldName, data);
        }
    }break;
    default:break;
    }
}

void FormModel::getData()
{
    for(const QString& fieldName : listFieldName){
        getData(fieldName, true);
    }
}

void FormModel::getChangedData()
{
    for(const QString& fieldName : listFieldName){
        getData(fieldName, false);
    }
}

void FormModel::setData()
{
    for(const QString& fieldName : listFieldName){
        QWidget *inputWidget = hashInputWidget.value(fieldName);
        switch (inputWidget->property("FormModelType").toInt()) {
        case QLineEditType: {
            QString data = table->getFieldValue(fieldName).toString();
            if(hashSetFilter.contains(QLineEditType)){
                data = hashSetFilter.value(QLineEditType)(data, inputWidget).toString();
            }
            dynamic_cast<QLineEdit*>(inputWidget)->setText(data);
        }break;
        case QTextEditType: {
            QString data = table->getFieldValue(fieldName).toString();
            if(hashSetFilter.contains(QTextEditType)){
                data = hashSetFilter.value(QTextEditType)(data, inputWidget).toString();
            }
            dynamic_cast<QTextEdit*>(inputWidget)->setText(data);
        }break;
        case QPlainTextEditType: {
            QString data = table->getFieldValue(fieldName).toString();
            if(hashSetFilter.contains(QPlainTextEditType)){
                data = hashSetFilter.value(QPlainTextEditType)(data, inputWidget).toString();
            }
            dynamic_cast<QPlainTextEdit*>(inputWidget)->setPlainText(data);
        }break;
        case QDateTimeEditType: {
            QString QDateTimeForceStringFormat = inputWidget->property("ForceString").toString();
            QDateTimeEdit* dateTimeEdit = dynamic_cast<QDateTimeEdit*>(inputWidget);
            if(QDateTimeForceStringFormat.isEmpty()){
                QDateTime data = table->getFieldValue(fieldName).toDateTime();
                if(hashSetFilter.contains(QDateTimeEditType)){
                    data = hashSetFilter.value(QDateTimeEditType)(data, inputWidget).toDateTime();
                }
                dateTimeEdit->setDateTime(data);
            }else{
                QString dateTimeString = table->getFieldValue(fieldName).toString();
                if(dateTimeString.isEmpty()){
                    dateTimeEdit->setDateTime(dateTimeEdit->minimumDateTime());
                }else{
                    QDateTime dateTime = QDateTime::fromString(dateTimeString, QDateTimeForceStringFormat);
                    if(hashSetFilter.contains(QDateTimeEditType)){
                        dateTime = hashSetFilter.value(QDateTimeEditType)(dateTime, inputWidget).toDateTime();
                    }
                    dateTimeEdit->setDateTime(dateTime);
                }
            }
        }break;
        case QComboBoxType: {
            QString data = table->getFieldValue(fieldName).toString();
            if(hashSetFilter.contains(QComboBoxType)){
                data = hashSetFilter.value(QComboBoxType)(data, inputWidget).toString();
            }
            dynamic_cast<QComboBox*>(inputWidget)->setCurrentText(data);
        }break;
        case QSpinBoxType: {
            int data = table->getFieldValue(fieldName).toInt();
            if(hashSetFilter.contains(QSpinBoxType)){
                data = hashSetFilter.value(QSpinBoxType)(data, inputWidget).toInt();
            }
            dynamic_cast<QSpinBox*>(inputWidget)->setValue(data);
        }break;
        case QDoubleSpinBoxType: {
            double data = table->getFieldValue(fieldName).toDouble();
            if(hashSetFilter.contains(QDoubleSpinBoxType)){
                data = hashSetFilter.value(QDoubleSpinBoxType)(data, inputWidget).toDouble();
            }
            dynamic_cast<QDoubleSpinBox*>(inputWidget)->setValue(data);
        }break;
        case QCheckBoxType: {
            bool data = table->getFieldValue(fieldName).toBool();
            if(hashSetFilter.contains(QCheckBoxType)){
                data = hashSetFilter.value(QCheckBoxType)(data, inputWidget).toBool();
            }
            dynamic_cast<QCheckBox*>(inputWidget)->setChecked(data);
        }break;
        case QTableWidgetItemType: {
            QTableWidgetItem* item = hashTableItem.value(fieldName);
            QString data = table->getFieldValue(fieldName).toString();
            if(hashSetFilter.contains(QTableWidgetItemType)){
                data = hashSetFilter.value(QTableWidgetItemType)(data, reinterpret_cast<QWidget*>(item)).toString();
            }
            item->setText(data);
        }break;
        default:break;
        }
    }
}

void FormModel::setReadOnly(bool isReadOnly)
{
    for(const QString& fieldName : listFieldName){
        QWidget *inputWidget = hashInputWidget.value(fieldName);
        switch (inputWidget->property("FormModelType").toInt()) {
        case QLineEditType: {
            dynamic_cast<QLineEdit*>(inputWidget)->setReadOnly(isReadOnly);
        }break;
        case QTextEditType: {
            dynamic_cast<QTextEdit*>(inputWidget)->setReadOnly(isReadOnly);
        }break;
        case QPlainTextEditType: {
            dynamic_cast<QPlainTextEdit*>(inputWidget)->setReadOnly(isReadOnly);
        }break;
        case QDateTimeEditType: {
            dynamic_cast<QDateTimeEdit*>(inputWidget)->setReadOnly(isReadOnly);
        }break;
        case QComboBoxType: {
        }break;
        case QSpinBoxType: {
            dynamic_cast<QSpinBox*>(inputWidget)->setReadOnly(isReadOnly);
        }break;
        case QDoubleSpinBoxType: {
            dynamic_cast<QDoubleSpinBox*>(inputWidget)->setReadOnly(isReadOnly);
        }break;
        case QCheckBoxType: {
            dynamic_cast<QCheckBox*>(inputWidget)->setCheckable(isReadOnly);
        }break;
        case QTableWidgetItemType: {
            QTableWidgetItem* item = hashTableItem.value(fieldName);
            Qt::ItemFlags flags = item->flags();
            flags.setFlag(Qt::ItemIsEditable, isReadOnly);
            item->setFlags(flags);
        }break;
        default:break;
        }
    }
}

bool FormModel::hasChange()
{
    return table->fieldChanged.size();
}
